package cn.itcast.nems.studentrecord.service.impl.studentrecord;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.ic.common.exception.v2.bean.BizStatusEnum;
import cn.itcast.nems.approval.dao.entity.ApprovalForm;
import cn.itcast.nems.approval.dao.mapper.ApprovalFormMapper;
import cn.itcast.nems.base.api.ClazzApi;
import cn.itcast.nems.base.dao.entity.E2Clazz;
import cn.itcast.nems.base.dao.mapper.E2ClazzMapper;
import cn.itcast.nems.base.dto.ClazzDTO;
import cn.itcast.nems.common.BasePageRequest;
import cn.itcast.nems.common.PageQueryModel;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.common.bean.KeyValue;
import cn.itcast.nems.common.constant.OrderStateEnum;
import cn.itcast.nems.common.enumeration.BizNumberTypeEnum;
import cn.itcast.nems.common.enumeration.NemsErrorBodyEnum;
import cn.itcast.nems.common.service.BizNumberService;
import cn.itcast.nems.common.util.NumberUtil;
import cn.itcast.nems.employee.dao.bean.EmployeeGroupsBean;
import cn.itcast.nems.journal.enumeration.JournalStateEnum;
import cn.itcast.nems.manager.msas.MsasManager;
import cn.itcast.nems.manager.util.CustomBeanUtil;
import cn.itcast.nems.oldems.dao.mapper.StudentJoinClassMapper;
import cn.itcast.nems.oldems.dto.StudentRecordClazzDTO;
import cn.itcast.nems.order.dao.dataobject.RefundClazzInfosDO;
import cn.itcast.nems.order.dao.entity.Order;
import cn.itcast.nems.order.dao.mapper.OrderMapper;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.dao.condition.StudentRecordParams;
import cn.itcast.nems.studentrecord.dao.dataobject.*;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordTransaction;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordMapper;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordOrderRelationshipMapper;
import cn.itcast.nems.studentrecord.dto.*;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordBalanceAmountDueMessageDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordMessageDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordRefundDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordTransactionCreateDTO;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordErrorBodyEnum;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordStateEnum;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordTransactionStateEnum;
import cn.itcast.nems.studentrecord.service.StudentRecordLockService;
import cn.itcast.nems.studentrecord.service.settlement.SettlementCalculator;
import cn.itcast.nems.studentrecord.service.settlement.SettlementData;
import cn.itcast.nems.studentrecord.service.settlement.SettlementResult;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordMessageService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordStudentRelationshipService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordTransactionService;
import cn.itcast.nems.studentrecord.util.StudentRecordServiceUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itcast.msas.sdk.acm.domain.AccountDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static cn.itcast.nems.journal.util.TransferUtils.formatAccount;
import static cn.itcast.nems.journal.util.TransferUtils.formatPrice;

@Service
@Slf4j
@RequiredArgsConstructor
public class StudentRecordServiceImpl extends ServiceImpl<StudentRecordMapper, StudentRecord> implements StudentRecordService {
    private final BizNumberService bizNumberService;
    private final StudentRecordMessageService studentRecordMessageService;
    private final StudentRecordOrderRelationshipMapper studentRecordOrderRelationshipMapper;
    private final E2ClazzMapper e2ClazzMapper;
    private final ClazzApi clazzApi;
    private final StudentRecordTransactionService studentRecordTransactionService;
    private final StudentRecordLockService studentRecordLockService;
    private final OrderMapper orderMapper;
    private final MsasManager msasManager;
    private final ApprovalFormMapper approvalFormMapper;
    private final StudentJoinClassMapper studentJoinClassMapper;
    private final StudentRecordStudentRelationshipService studentRecordStudentRelationshipService;

    @Override
    public StudentRecord suspensionStudentRecord(String studentRecordId) {
        StudentRecord studentRecord = getBaseMapper().selectById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "学籍ID：" + studentRecordId));
        if (ReferenceTypeEnum.SUSPENSION.name().equals(studentRecord.getSource())) {
            ClazzDTO originClazzDTO = clazzApi.queryByClassId(studentRecord.getClazzId());
            Assert.notNull(originClazzDTO, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "【审批完成】重读凭单原学籍班级ID：" + studentRecord.getClazzId()));
            log.info("【审批完成】重读凭单原学籍来源：{}，是否为休学班级：{}", studentRecord.getSource(), originClazzDTO.getSuspensionFlag());
            if (org.springframework.util.StringUtils.hasText(studentRecord.getAssociatedRecordId())) {
                StudentRecord suspensionOriginStudentRecord = getBaseMapper().selectById(studentRecordId);
                Assert.notNull(suspensionOriginStudentRecord, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "休学原学籍ID：" + suspensionOriginStudentRecord.getId()));
                log.info("当前学籍ID：{}，班级ID：{},休学原学籍ID：{}, 原学籍对应班级ID：{}",
                        studentRecord.getId(), studentRecord.getClazzId(),
                        suspensionOriginStudentRecord.getId(), suspensionOriginStudentRecord.getClazzId());
                studentRecord = suspensionOriginStudentRecord ;
            }
        }
        return studentRecord;
    }

    @Override
    public void validateAmount(final StudentRecord studentRecord, int amount, String state) {
        if (StringUtils.isEmpty(state) || JournalStateEnum.DRAFT.name().equalsIgnoreCase(state)) {
            return;
        }
        int paidTotal = studentRecord.getPaidAmount() + studentRecord.getTransferFromAmount() - studentRecord.getRefundAmount();
        if (!ReferenceTypeEnum.DROPOUT.name().equals(studentRecord.getSettlementReason()) && studentRecord.getTransferOutAmount() != null) {
            paidTotal = paidTotal - studentRecord.getTransferOutAmount();
        }
        log.info("校验退费凭单退费金额， 学生可用退费金额：{} ，凭单退费金额：{}", paidTotal, amount);
        if (amount > paidTotal) {
            BizExceptionProducer.throwProduce(StudentRecordErrorBodyEnum.REFUND_AMOUNT_OUT_PAID, NumberUtil.convertToYuan(paidTotal) , NumberUtil.convertToYuan(amount));
        }
    }

    @Override
    public List<StudentRecordDO> findValidStudentRecordByStudentId(Integer studentId) {
        return getBaseMapper().findValidStudentRecordByStudentId(studentId);
    }

    @Override
    public Map<String, Integer> findStudentIds(Set<String> studentRecordIds) {
        if (studentRecordIds == null || studentRecordIds.isEmpty()) {
            return Collections.emptyMap();
        }
        final List<Map<String, Object>> rows = super.getBaseMapper().findStudentIds(studentRecordIds);
        Map<String, Integer> result = new HashMap<>();
        if (!rows.isEmpty()) {
            rows.forEach(row -> {
                String studentRecordId = (String) row.get("studentRecordId");
                Integer studentId = (Integer) row.get("studentId");
                result.put(studentRecordId, studentId);
            });
        }
        return result;
    }

    @Override
    @Cacheable(cacheNames = "EMSV2:StudentIdByID", key = "#id", unless = "#result == null")
    public Integer getStudentIdByID(String id) {
        return getBaseMapper().getStudentIdByID(id);
    }

    @Override
    public List<StudentRecord> findStudentRecordListByStudentId(Integer studentId, Set<String> excludeIds) {
        return getBaseMapper().findStudentRecordListByStudentId(studentId, excludeIds);
    }

    @Override
    public void invalidStudentRecord(String studentRecordId) {
        StudentRecord update = new StudentRecord();
        update.setId(studentRecordId);
        update.setState(StudentRecordStateEnum.INVALID.name());
        super.getBaseMapper().updateById(update);
    }

    @Override
    public int findValidStudentRecordCount(int clazzId) {
        return super.getBaseMapper().selectValidStudentRecordCount(clazzId, LocalDateTime.now());
    }

    @Override
    public List<StudentRecordMessageDTO> findOutStudentRecords(LocalDate outDate) {
        LocalDateTime startDateTime = outDate.atStartOfDay();
        LocalDateTime endDateTime = outDate.atTime(23, 59, 59);
        final List<StudentRecord> studentRecords = super.getBaseMapper().selectOutStudentRecords(startDateTime, endDateTime);
        if (studentRecords == null || studentRecords.isEmpty()) {
            return Collections.emptyList();
        }
        return studentRecords
                .stream()
                .map(sr -> {
                    StudentRecordMessageDTO dto = new StudentRecordMessageDTO();
                    dto.setStudentRecordId(sr.getId());
                    dto.setClazzId(sr.getClazzId());
                    dto.setBizDateTime(sr.getSettlementDate());
                    dto.setTenantId(sr.getTenantId());
                    dto.setSubtenantId(sr.getSubtenantId());
                    return dto;
                })
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void addStudentRecord(StudentRecord studentRecord) {
        final String id = bizNumberService.next(BizNumberTypeEnum.STUDENT_RECORD_NO);
        studentRecord.setId(id);
        final String uniqueCode = bizNumberService.next(BizNumberTypeEnum.STUDENT_RECORD_UNIQUE_CODE);
        studentRecord.setUniqueCode(uniqueCode);
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        studentRecord.setBalanceAmountDue(balanceAmountDue);
        super.getBaseMapper().insert(studentRecord);
        this.sentBalanceAmountDueChangeMessage(studentRecord, 0);
    }

    @Override
    public StudentRecord findInClazzStudentRecord(int studentId, int clazzId) {
        return super.getBaseMapper().selectInClazzByStudentIdClazzId(studentId, clazzId);
    }

    @Override
    public StudentRecord findStudentRecord(int studentId, int clazzId) {
        final List<StudentRecord> studentRecords = super.getBaseMapper().selectByStudentIdClazzId(studentId, clazzId);
        if (studentRecords.isEmpty()) {
            return null;
        }
        if (studentRecords.size() == 1) {
            return studentRecords.get(0);
        }
        return studentRecords
                .stream()
                .filter(sr -> !StudentRecordStateEnum.INVALID.name().contentEquals(sr.getState()))
                .findAny()
                .orElse(studentRecords.get(0));
    }

    @Override
    public void updateStudentRecordById(StudentRecord update) {
        Assert.notBlank(update.getId(), BizExceptionProducer.serverError("缺少学籍ID"));
        super.getBaseMapper().updateById(update);
    }

    @Override
    public void batchUpdateById(List<StudentRecord> updateCmds) {
        super.updateBatchById(updateCmds);
    }

    @Override
    public StudentRecord getById(String id) {
        return super.getBaseMapper().selectById(id);
    }

    @Override
    public StudentRecord getStudentRecordById(String id) {
        StudentRecord studentRecord = lambdaQuery().eq(StudentRecord::getId, id).one();
        if (studentRecord == null) {
            return null;
        }
        if (null == studentRecord.getPaidAmount()) {
            studentRecord.setPaidAmount(0);
        }
        if (null == studentRecord.getAmountDue()) {
            studentRecord.setAmountDue(0);
        }
        if (null == studentRecord.getTransferFromAmount()) {
            studentRecord.setTransferFromAmount(0);
        }
        if (null == studentRecord.getRefundAmount()) {
            studentRecord.setRefundAmount(0);
        }
        if (null == studentRecord.getTransferOutAmount()) {
            studentRecord.setTransferOutAmount(0);
        }
        return studentRecord;
    }

    @Override
    public List<StudentRecord> getByIds(Collection<String> ids) {
        return super.getBaseMapper().selectBatchIds(ids);
    }

    @Override
    public String findOrderId(String studentRecordId) {
        final Set<String> orderIds = this.studentRecordOrderRelationshipMapper.selectOrderIds(studentRecordId);
        String orderId = null;
        if (orderIds != null && !orderIds.isEmpty()) {
            orderId = orderIds.iterator().next();
        }
        return orderId;
    }

    @Override
    public StudentRecord findStudentRecord(String orderId) {
        return super.getBaseMapper().selectStudentRecordByOrderId(orderId);
    }

    @Override
    @Transactional
    public SettlementResult studentRecordSettlement(String studentRecordId,
                                                    final LocalDate settlementDate,
                                                    SettlementCalculator calculator) {
        final StudentRecord studentRecord = super.getBaseMapper().selectById(studentRecordId);
        final SettlementResult settlementResult = this.calSettlementResult(studentRecord, settlementDate, calculator);

        StudentRecord update = new StudentRecord();
        update.setId(studentRecordId);
        // update.setLockFlag(false);
        if (calculator.isRenewal()) {
            update.setRenewalFlag(true);
        }
        update.setSettlementDate(settlementDate.atStartOfDay());
        update.setSettlementReason(settlementResult.getSettlementReason());
        update.setSettlementAmount(settlementResult.getSettlementAmount());
        update.setSettlementDays(settlementResult.getSettlementDays());
        update.setActualAmountDue(settlementResult.getSettlementAmount());
        Integer transferOutAmount = studentRecord.getTransferOutAmount();
        transferOutAmount = transferOutAmount == null ? 0 : transferOutAmount;
        final Integer transferAmount = settlementResult.getTransferAmount();
        if (transferAmount != null && transferAmount != 0) {
            transferOutAmount += transferAmount;
        }
        update.setTransferOutAmount(transferOutAmount);
        update.setRefundAmount(settlementResult.getSettlementData().getRefundAmount());
        studentRecord.setSettlementReason(settlementResult.getSettlementReason());
        studentRecord.setTransferOutAmount(transferOutAmount);
        studentRecord.setActualAmountDue(settlementResult.getSettlementAmount());
        studentRecord.setRefundAmount(update.getRefundAmount());
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        update.setBalanceAmountDue(balanceAmountDue);
        log.info("StudentRecordSettlement update {}", update);
        super.getBaseMapper().updateById(update);
        this.sentBalanceAmountDueChangeMessage(studentRecord, studentRecord.getBalanceAmountDue());
        return settlementResult;
    }

    private SettlementResult calSettlementResult(StudentRecord studentRecord,
                                                 final LocalDate outDate,
                                                 SettlementCalculator calculator) {
        SettlementData settlementData = new SettlementData();
        BeanUtils.copyProperties(studentRecord, settlementData);
        final ClazzDTO clazzDTO = this.clazzApi.queryByClassId(studentRecord.getClazzId());
        settlementData.setClazzId(clazzDTO.getClassId());
        settlementData.setSettlementDate(outDate.atStartOfDay());
        settlementData.setStartDate(clazzDTO.getStartDate());
        settlementData.setPredictionGraduationDate(clazzDTO.getPredictionGraduationDate());
        settlementData.setDelayFlag(clazzDTO.getDelayFlag());
        settlementData.setSuspensionFlag(clazzDTO.getDelayFlag());
        return calculator.calculate(settlementData);
    }

    @Override
    @Transactional
    public boolean paid(String studentRecordId, int amount) {
        if (amount < 0) {
            BizExceptionProducer.throwBadRequest(BizStatusEnum.BAD_REQUEST.name(), "学籍(%s)支付金额(%d)不能<0", studentRecordId, amount);
        }
        final StudentRecord studentRecord = super.getBaseMapper().selectById(studentRecordId);
        studentRecord.setPaidAmount(studentRecord.getPaidAmount() + amount);
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        StudentRecord update = new StudentRecord();
        update.setId(studentRecordId);
        update.setPaidAmount(studentRecord.getPaidAmount());
        update.setBalanceAmountDue(balanceAmountDue);
        super.getBaseMapper().updateById(update);
        this.sentBalanceAmountDueChangeMessage(studentRecord, studentRecord.getBalanceAmountDue());
        return update.getPaidAmount() >= studentRecord.getActualAmountDue();
    }

    @Override
    @Transactional
    public void refund(String studentRecordId, int amount) {
        if (amount < 0) {
            BizExceptionProducer.throwBadRequest(BizStatusEnum.BAD_REQUEST.name(), "学籍(%s)支付金额(%d)不能<0", studentRecordId, amount);
        }
        final StudentRecord studentRecord = super.getBaseMapper().selectById(studentRecordId);
        this.doRefund(studentRecord, amount ,true);
    }

    @Override
    @Transactional
    public void refund(StudentRecordRefundDTO refundDTO ,boolean isCheckAmount) {
        final StudentRecord studentRecord = super.getBaseMapper().selectById(refundDTO.getStudentRecordId());
        this.doRefund(studentRecord, refundDTO.getRefundAmount(),isCheckAmount);
    }

    private void doRefund(StudentRecord studentRecord, int amount , boolean isCheckAmount) {
        if(isCheckAmount) {
            int paidAmountNew = studentRecord.getPaidAmount() + studentRecord.getTransferFromAmount() - studentRecord.getRefundAmount();
            if (!ReferenceTypeEnum.DROPOUT.name().equals(studentRecord.getSettlementReason())
                    && studentRecord.getTransferOutAmount() != null) {
                paidAmountNew = paidAmountNew - studentRecord.getTransferOutAmount();
            }
            if (amount > paidAmountNew) {
                BizExceptionProducer.throwProduce(StudentRecordErrorBodyEnum.REFUND_AMOUNT_OUT_PAID);
            }
        }
        studentRecord.setRefundAmount(studentRecord.getRefundAmount() + amount);
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        StudentRecord update = new StudentRecord();
        update.setId(studentRecord.getId());
        update.setRefundAmount(studentRecord.getRefundAmount());
        update.setBalanceAmountDue(balanceAmountDue);
        update.setActualAmountDue(studentRecord.getActualAmountDue());
        super.getBaseMapper().updateById(update);
        this.sentBalanceAmountDueChangeMessage(studentRecord, studentRecord.getBalanceAmountDue());
    }

    @Override
    @Transactional
    public void locks(Set<String> studentRecordIds, ReferenceTypeEnum referenceType, String referenceId) {
        final List<KeyValue<String, Boolean>> lockFlags = super.getBaseMapper().selectLockFlags(studentRecordIds);
        lockFlags
                .stream()
                .filter(KeyValue::getValue)
                .findAny()
                .ifPresent(kv -> BizExceptionProducer.throwProduce(StudentRecordErrorBodyEnum.STUDENT_RECORD_LOCKED, kv.getKey()));
        super.getBaseMapper().updateLockFlags(studentRecordIds, true, AccountHolder.getRequiredAccountInfo().getEmail());
        studentRecordIds.forEach(item -> {
            studentRecordLockService.lock(new StudentRecordLockDTO(item, referenceType.name(), referenceId));
        });

    }

    @Override
    @Transactional
    public void unlocks(Set<String> studentRecordIds, ReferenceTypeEnum referenceType, String referenceId) {
        final String referenceTypeName = Objects.nonNull(referenceType) ? referenceType.name() : null;
        super.getBaseMapper().updateLockFlags(studentRecordIds, false, AccountHolder.getRequiredAccountInfo().getEmail());
        studentRecordIds.forEach(item -> {
            studentRecordLockService.unlock(new StudentRecordLockDTO(item, referenceTypeName, referenceId));
        });
    }

    @Override
    @Transactional
    public void unlock(String studentRecordId) {
        super.getBaseMapper().updateLockFlags(Set.of(studentRecordId), false, AccountHolder.getRequiredAccountInfo().getEmail());
        studentRecordLockService.unlock(new StudentRecordLockDTO(studentRecordId, null, null));
    }


    @Override
    public List<StudentRecordDTO> queryByStudentIdAndClassId(Set<Integer> studentIds, Set<Integer> clazzIds) {
        List<StudentRecordDO> list = getBaseMapper().queryByStudentIdAndClassId(studentIds, clazzIds);
        return CollectionUtil.isEmpty(list) ? null :
                list.stream().map(StudentRecordServiceUtil::convert).collect(Collectors.toList());
    }

    @Override
    public Page<StudentRecordDTO> pageQuery(@NonNull PageQueryModel<StudentRecordQueryDTO> queryParam) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<StudentRecordDO> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
        page.setCurrent(queryParam.getPageNumber());
        page.setSize(queryParam.getPageSize());
        StudentRecordDO recordDO = CustomBeanUtil.copyProperties(queryParam.getCondition(), new StudentRecordDO());
        log.debug("学籍分页查询, 请求参数:{}", queryParam);
        if ((recordDO.getExcludeFlag() != null && recordDO.getExcludeFlag()) && !AccountHolder.hasEmployeeGroups()) {
            return Page.of(queryParam.getPageNumber(), queryParam.getPageSize(), 0, null);
        }
        recordDO.setEmployeeGroups(AccountHolder.getEmployeeGroups());
        if (recordDO.getStudentId() != null) {
            recordDO.setStudentIds(Set.of(recordDO.getStudentId()));
        }
        IPage<StudentRecordDO> pageData = super.getBaseMapper().findPageList(page, recordDO);
        log.debug("学籍分页查询, pages:{}, size:{}, current:{}, total:{}, pageDate.size():{}", pageData.getPages(), pageData.getSize(), pageData.getCurrent(), pageData.getTotal(), pageData.getRecords().size());
        if (CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(queryParam.getPageNumber(), queryParam.getPageSize(), 0, null);
        }
        return Page.of(queryParam.getPageNumber(),
                queryParam.getPageSize(),
                (int) pageData.getTotal(),
                pageData.getRecords().stream().map(StudentRecordServiceUtil::convert).toList()
        );
    }

    /**
     * 根据条件获取学籍数据<br>
     * <font color="red">多用于数据量较少的查询</font>
     *
     * @param condition         条件
     * @param checkResultExists 校验结果是否存在
     * @return 学籍数据
     */
    private List<StudentRecordDTO> queryByCondition(@NonNull StudentRecordQueryDTO condition, boolean checkResultExists) {
        PageQueryModel<StudentRecordQueryDTO> queryModel = new PageQueryModel<>();
        queryModel.convert();
        queryModel.setCondition(condition);
        Page<StudentRecordDTO> result = this.pageQuery(queryModel);
        Assert.notNull(result, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.NOT_EXISTS));
        if (checkResultExists) {
            Assert.isTrue(CollectionUtil.isNotEmpty(result.getRecords()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.NOT_EXISTS));
        }
        return result.getRecords();
    }

    @Override
    public @NonNull
    StudentRecordDTO queryById(@NonNull String id) {
        Assert.isTrue(StringUtils.isNotEmpty(id), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        StudentRecordQueryDTO condition = new StudentRecordQueryDTO();
        condition.setId(id);
        condition.setIncludeInvalid(Boolean.TRUE);
        condition.setIncludeWaitDeleted(Boolean.TRUE);
        return this.queryByCondition(condition, Boolean.TRUE).get(0);
    }

    @Override
    public @NonNull StudentRecordDTO queryByUniqueCode(@NonNull String uniqueCode) {
        Assert.isTrue(StringUtils.isNotEmpty(uniqueCode), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        StudentRecordQueryDTO condition = new StudentRecordQueryDTO();
        condition.setUniqueCode(uniqueCode);
        condition.setIncludeInvalid(Boolean.TRUE);
        condition.setIncludeWaitDeleted(Boolean.TRUE);
        return this.queryByCondition(condition, Boolean.TRUE).get(0);
    }

    @Override
    public List<StudentRecordDTO> queryByStudentNo(@NonNull String studentNo) {
        Assert.isTrue(StringUtils.isNotEmpty(studentNo), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        StudentRecordQueryDTO condition = new StudentRecordQueryDTO();
        condition.setStudentNo(studentNo);
        condition.setIncludeInvalid(Boolean.TRUE);
        condition.setIncludeWaitDeleted(Boolean.TRUE);
        return this.queryByCondition(condition, Boolean.FALSE);
    }

    @Override
    public List<StudentRecordDTO> queryByStudentIds(Set<Integer> studentIds, String state) {
        Assert.isTrue(CollectionUtil.isNotEmpty(studentIds), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<StudentRecordDO> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
        page.setCurrent(1);
        page.setSize(Integer.MAX_VALUE);
        StudentRecordDO condition = new StudentRecordDO();
        condition.setStudentIds(studentIds);
        condition.setIncludeInvalid(Boolean.TRUE);
        condition.setIncludeWaitDeleted(Boolean.TRUE);
        condition.setState(state);
        IPage<StudentRecordDO> pageData = super.getBaseMapper().findPageList(page, condition);
        if (null == pageData || CollectionUtil.isEmpty(pageData.getRecords())) {
            return null;
        }
        return pageData.getRecords().stream().map(StudentRecordServiceUtil::convert).toList();
    }

    @Override
    public void updateAdjustmentAmount(@NonNull String studentRecordId, @NonNull Integer adjustmentAmount) {
        Assert.isTrue(StringUtils.isNotEmpty(studentRecordId), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        Assert.notNull(adjustmentAmount, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        this.baseMapper.updateAdjustmentAmount(studentRecordId, adjustmentAmount);
        var record = super.getById(studentRecordId);
        StudentRecord update = new StudentRecord();
        update.setId(studentRecordId);
        update.setBalanceAmountDue(this.calBalanceAmountDue(record));
        super.getBaseMapper().updateById(update);
        this.sentBalanceAmountDueChangeMessage(record, record.getBalanceAmountDue());
    }

    @Override
    public List<String> findSchoolIdsByRecordId(@NotNull StudentRecordDO recordDO) {
        return getBaseMapper().findSchoolIdsByRecordId(recordDO);
    }

    @Override
    public List<String> queryOrderIdsByStudentRecordId(@NonNull String studentRecordId) {
        Assert.isTrue(StringUtils.isNotEmpty(studentRecordId), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.PARAMS_ERROR));
        return this.baseMapper.queryOrderIdsByStudentRecordId(studentRecordId);
    }

    @Override
    public List<StudentRecordInfoDO> listStudentRecordInfo(Integer studentId) {
        return listStudentRecordInfo(studentId, null, null);
    }

    @Override
    public List<StudentRecordInfoDO> listStudentRecordInfoByStudentRecordId(Integer studentId, String studentRecordId) {
        return listStudentRecordInfo(studentId, null, studentRecordId);
    }

    @Override
    public List<StudentRecordClazzDTO> findClazzByStudentId(@NonNull Integer studentId,
                                                            Boolean delayFlag,
                                                            Boolean suspensionFlag,
                                                            Boolean upgradeable) {
        //        if (!AccountHolder.hasEmployeeGroups()) {
        //            return null;
        //        }
        List<StudentClazzDO> list = getBaseMapper().findClazzByStudentId(
                new StudentRecordParams(
                        null, null, null, studentId,
                        List.of(ReferenceTypeEnum.DROPOUT.name(), ReferenceTypeEnum.FINAL.name())),
                delayFlag, suspensionFlag, upgradeable,
                null
        );
        return CollectionUtil.isEmpty(list) ? null :
                list.stream().map(item -> CustomBeanUtil.copyProperties(item, new StudentRecordClazzDTO())).collect(Collectors.toList());
    }

    @Override
    public List<ClazzLockRecordDO> findClazzLockRecordListByClazzId(Integer clazzId, List<String> ids) {
        return getBaseMapper().findClazzLockRecordListByClazzId(clazzId, ids);
    }

    @Override
    public List findNotInClazzRecord(Integer clazzId, List<String> studentRecordIds) {
        return getBaseMapper().selectObjs(
                new LambdaQueryWrapper<StudentRecord>()
                        .select(StudentRecord::getId)
                        .eq(StudentRecord::getClazzId, clazzId)
                        .in(CollectionUtil.isNotEmpty(studentRecordIds), StudentRecord::getId, studentRecordIds)
                        .isNull(StudentRecord::getSettlementDate)
                        .eq(StudentRecord::getLockFlag, true)
                        .eq(StudentRecord::getDeletedFlag, false)
        );
    }

    @Override
    public List<StudentRecordInfoDO> listStudentRecordInfo(Integer studentId, Integer clazzId, String studentRecordId) {
        return baseMapper.listStudentRecordInfo(studentId, clazzId, studentRecordId);
    }

    @Override
    public List<StudentRecordInfoDO> listStudentRecordInfoByjournalRefundId(String studentRecordId, Integer clazzId) {
        return baseMapper.listStudentRecordInfoByjournalRefundId(studentRecordId, clazzId);
    }

    @Override
    public int findInClazzCount(Integer clazzId) {
        return 0;
    }

    public Page<SpecialClazz> findSpecialClazzPage(BasePageRequest<SpecialClazzQuery> query) {
        EmployeeGroupsBean employeeGroups = AccountHolder.getRequiredAccountEmployeeGroups();
        if (employeeGroups.getGroupList().isEmpty()) {
            return Page.of(query.getPageNumber(), query.getPageSize(), 0, new ArrayList<>());
        }
        query.getCondition().setEmployeeGroups(employeeGroups.getGroupList());
        var dbPage = baseMapper.findSpecialClazzPage(
                query.getCondition(),
                com.baomidou.mybatisplus.extension.plugins.pagination.Page.of(query.getPageNumber(), query.getPageSize())
        );
        return Page.of(
                (int) dbPage.getCurrent(),
                (int) dbPage.getSize(),
                (int) dbPage.getTotal(),
                mapPage(dbPage.getRecords())
        );
    }

    private List<SpecialClazz> mapPage(List<SpecialClazz> records) {
        for (SpecialClazz record : records) {
            record.setFrozeAmountSumFormatted(formatPrice(record.getFrozeAmountSum()));
            record.setPendingAmountSumFormatted(formatPrice(record.getPendingAmountSum()));
        }
        return records;
    }

    @Override
    public SpecialClazz findSpecialClazzById(Integer clazzId) {
        var sc = baseMapper.findSpecialClazzById(clazzId);
        if (sc == null) {
            E2Clazz clazz = e2ClazzMapper.selectOne(new QueryWrapper<E2Clazz>()
                    .lambda()
                    .eq(E2Clazz::getClazzId, clazzId));
            sc = new SpecialClazz();
            sc.setClazzId(clazz.getClazzId());
            sc.setClazzName(clazz.getClazzName());
            sc.setSchoolCode(clazz.getSchoolCode());
            sc.setSchoolName(clazz.getSchoolName());
            sc.setSubjectId(clazz.getSubjectId());
            sc.setSubjectName(clazz.getSubjectName());
            sc.setFrozeAmountSumFormatted(formatPrice(0));
            sc.setPendingAmountSumFormatted(formatPrice(0));
            sc.setPredictionGraduationDate(clazz.getPredictionGraduationDate());
            sc.setGraduationDate(clazz.getGraduationDate());
            sc.setUpgradeable(clazz.getUpgradeable());
        } else {
            sc.setPendingAmountSumFormatted(formatPrice(sc.getPendingAmountSum()));
            sc.setFrozeAmountSumFormatted(formatPrice(sc.getFrozeAmountSum()));
        }
        return sc;
    }

    @Override
    public List<RefundClazzInfosDO> listRefundClazzInfos(String studentRecordId) {
        return null;
    }

    @Override
    public List<StudentRecordChangeWithClazzStartDateDTO> findBeforeStartDateByClazzId(Integer clazzId, String startDate) {
        List<StudentRecordDO> list = getBaseMapper().findBeforeStartDateByClazzId(clazzId, startDate);
        LocalDateTime afterDatetime = LocalDateTimeUtil.parse(startDate, "yyyy-MM-dd HH:mm:ss");
        return CollectionUtil.isEmpty(list) ? null :
                list.stream().map(item ->
                                StudentRecordChangeWithClazzStartDateDTO.buildApiParam(
                                        item.getId(),
                                        item.getClazzId(),
                                        item.getClazzName(),
                                        afterDatetime,
                                        item.getInDate(),
                                        item.getGraduationDate(),
                                        item.getActualAmountDue()))
                        .toList();
    }


    /**
     * 计算剩余应付金额，剩余应付 = 实际应付 - （已付金额 + 转班转入金额 - 退费金额 - 转班转出费用）
     *
     * @param studentRecord 学籍
     * @return 剩余应付金额
     * @author 李勇
     */
    private int calBalanceAmountDue(StudentRecord studentRecord) {
        // 转班转出金额
        int transferOutAmount = calTransferOutAmount(studentRecord);
        log.info("计算'剩余应付'，转出金额:{} 学籍:{}", transferOutAmount, studentRecord);
        return studentRecord.getActualAmountDue()
                + studentRecord.getRefundAmount()
                + transferOutAmount
                - studentRecord.getPaidAmount()
                - studentRecord.getTransferFromAmount();
    }

    /**
     * 功能描述：计算转班转出金额 <br/>
     * 只有在结算出班类型为 “转移”、“转班”、“休学”、“待定” 时，结算余额才为 “转班转出金额”，其他情况实际为”退费“<p/>
     * 注：通常只有在出班以后再操作学籍（如退费）才会出现该情况。
     *
     * @param studentRecord 学籍
     * @return 转班转出金额
     * @author 刘曙
     * @since 2023年12月13日
     * <p>
     * update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    private int calTransferOutAmount(StudentRecord studentRecord) {
        Integer transferOutAmount = 0;

        String settlementReason = studentRecord.getSettlementReason();
        if (ReferenceTypeEnum.TRANSFER.name().equalsIgnoreCase(settlementReason) ||
                ReferenceTypeEnum.EXCHANGE.name().equalsIgnoreCase(settlementReason) ||
                ReferenceTypeEnum.SUSPENSION.name().equalsIgnoreCase(settlementReason) ||
                ReferenceTypeEnum.FUND_TRANSFER.name().equalsIgnoreCase(settlementReason) ||
                ReferenceTypeEnum.DELAY.name().equalsIgnoreCase(settlementReason)) {
            transferOutAmount = studentRecord.getTransferOutAmount();
        }

        return transferOutAmount;
    }

    private void sentBalanceAmountDueChangeMessage(StudentRecord studentRecord, int beforeBalanceAmountDue) {
        final Integer afterBalanceAmountDue = studentRecord.getBalanceAmountDue();
        if (afterBalanceAmountDue == beforeBalanceAmountDue) {
            return;
        }
        StudentRecordBalanceAmountDueMessageDTO dto = new StudentRecordBalanceAmountDueMessageDTO();
        dto.setStudentRecordId(studentRecord.getId());
        dto.setClazzId(studentRecord.getClazzId());
        dto.setBizDateTime(LocalDateTime.now());
        dto.setTenantId(studentRecord.getTenantId());
        dto.setSubtenantId(studentRecord.getSubtenantId());
        dto.setAfterBalanceAmountDue(afterBalanceAmountDue);
        dto.setBeforeBalanceAmountDue(beforeBalanceAmountDue);
        this.studentRecordMessageService.sendBalanceAmountDueChange(dto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateInDateByIds(@NonNull String studentRecordId, @NonNull LocalDateTime startDate) {
        StudentRecord studentRecord = getBaseMapper().selectById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "学籍ID：" + studentRecord.getId()));
        Assert.isNull(studentRecord.getSettlementDate(), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.SETTLEMENT_DATE_NOT_EMPTY, LocalDateTimeUtil.formatNormal(studentRecord.getSettlementDate())));
        ClazzDTO clazzDTO = clazzApi.queryByClassId(studentRecord.getClazzId());
        Assert.notNull(clazzDTO, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "班级ID：" + studentRecord.getClazzId()));
        // 出班学籍流转
        StudentRecordTransactionCreateDTO createDTO = this.wrapStudentRecordTransactionCreateDTO(
                startDate,
                studentRecord.getInDate(),
                studentRecord.getClazzId(),
                clazzDTO.getClassName(),
                studentRecord.getId(),
                studentRecord.getActualAmountDue(),
                clazzDTO.getGraduationTime(),
                StudentRecordTransaction.TYPE_OUT);
        log.info("【监听班级开班时间变更消息】出班学籍流转记录：{}", JSON.toJSONString(createDTO));
        studentRecordTransactionService.createStudentRecordTransaction(createDTO);
        // 进班学籍流转
        createDTO = this.wrapStudentRecordTransactionCreateDTO(
                startDate,
                studentRecord.getInDate(),
                studentRecord.getClazzId(),
                clazzDTO.getClassName(),
                studentRecord.getId(),
                studentRecord.getActualAmountDue(),
                clazzDTO.getGraduationTime(),
                StudentRecordTransaction.TYPE_IN);
        log.info("【监听班级开班时间变更消息】进班学籍流转记录：{}", JSON.toJSONString(createDTO));
        studentRecordTransactionService.createStudentRecordTransaction(createDTO);
        // 早于EMS修改后【开班时间】的学籍 ， 进班时间修改为该时间
        getBaseMapper().update(null,
                new LambdaUpdateWrapper<StudentRecord>()
                        .eq(StudentRecord::getId, studentRecord.getId())
                        .set(StudentRecord::getInDate, startDate));
    }

    private StudentRecordTransactionCreateDTO wrapStudentRecordTransactionCreateDTO(
            LocalDateTime startDate,
            LocalDateTime inDate,
            Integer clazzId,
            String clazzName,
            String studentRecordId,
            Integer actualAmountDue,
            LocalDate graduationDate,
            int type) {
        StudentRecordTransactionCreateDTO createDTO = new StudentRecordTransactionCreateDTO();
        // 出班时间为原学籍进班时间 、进班时间为修改后的班级开始时间
        if (StudentRecordTransaction.TYPE_IN.equals(type)) {
            createDTO.setBizDate(startDate);
        } else {
            createDTO.setBizDate(inDate);
        }
        createDTO.setClazzId(clazzId);
        createDTO.setStudentRecordId(studentRecordId);
        // TODO 默认第一阶段
        createDTO.setPhaseNumber(1);
        createDTO.setClassName(clazzName);
        createDTO.setReferenceType(ReferenceTypeEnum.CLAZZ_START_DATE_CHANGE);
        createDTO.setType(type);
        createDTO.setState(StudentRecordTransactionStateEnum.VALID);
        createDTO.setReferenceId("");
        createDTO.setActualAmountDue(actualAmountDue);
        createDTO.setSettlementDays(0);
        createDTO.setSettlementAmount(0);
        // 服务天数 （原学籍出班结算日期-新的进班日期 +1 ）
        if (Objects.nonNull(startDate) && Objects.nonNull(graduationDate)) {
            final long days = ChronoUnit.DAYS.between(startDate, LocalDateTime.of(graduationDate, LocalTime.MIN)) + 1;
            createDTO.setServiceDays((int) days);
        }
        return createDTO;
    }

    @Override
    public List<StudentRecordWithStudentDTO> findInClazzStudentRecord(int clazzId) {
        List<StudentRecordWithStudentDO> records = getBaseMapper().selectInclazzByClazzId(clazzId);

        List<StudentRecordWithStudentDTO> rst = null;
        if (!CollectionUtils.isEmpty(records)) {
            rst = records.stream().map(r -> {
                StudentRecordWithStudentDTO srd = new StudentRecordWithStudentDTO();
                BeanUtils.copyProperties(r, srd);
                return srd;
            }).toList();
        }
        return rst;
    }

    @Override
    public List<StudentRecordJournalVo> journals(Integer studentId, String studentRecordId) {
        var vos = getBaseMapper().findStudentRecordJournals(studentRecordId).stream().map(this::mapModel).collect(Collectors.toList());
        processVos(vos);
        return vos;
    }

    // 费用转移专业：修改学籍 e2_student_record “转出金额 transfer_out_amount”
    @Override
    public void updateTransferOutAmount(String studentRecordId, Integer transferAmount) {
        StudentRecord studentRecord = this.getStudentRecordById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "学籍ID：" + studentRecord.getId()));
        // 金额
        Integer amount = studentRecord.getTransferOutAmount() != null ? studentRecord.getTransferOutAmount() + transferAmount : transferAmount;
        studentRecord.setTransferOutAmount(amount);
        studentRecord.setSettlementReason(ReferenceTypeEnum.FUND_TRANSFER.name());
        // 计算剩余应付金额，剩余应付 = 实际应付 - （已付金额 + 转班转入金额 - 退费金额 - 转班转出费用）
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        // // 待生效的学籍，在有金额转入后，变为已生效学籍
        lambdaUpdate()
                .set(!StudentRecordStateEnum.VALID.name().equals(studentRecord.getState()), StudentRecord::getState, StudentRecordStateEnum.VALID.name())
                .set(StudentRecord::getTransferOutAmount, amount)
                .set(StudentRecord::getBalanceAmountDue, balanceAmountDue)
                .eq(StudentRecord::getId, studentRecordId)
                .update();
        this.sentBalanceAmountDueChangeMessage(studentRecord, balanceAmountDue);
    }

    // 费用转移专业：修改学籍 e2_student_record "转入金额 transfer_from_amount"
    @Override
    public void updateTransferFromAmount(String studentRecordId, Integer transferAmount) {
        StudentRecord studentRecord = this.getStudentRecordById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "学籍ID：" + studentRecord.getId()));
        // 已付金额
        Integer amount = studentRecord.getTransferFromAmount() != null ? studentRecord.getTransferFromAmount() + transferAmount : transferAmount;
        studentRecord.setTransferFromAmount(amount);
        studentRecord.setSettlementReason(ReferenceTypeEnum.FUND_TRANSFER.name());
        // 计算剩余应付金额，剩余应付 = 实际应付 - （已付金额 + 转班转入金额 - 退费金额 - 转班转出费用）
        final int balanceAmountDue = this.calBalanceAmountDue(studentRecord);
        // 待生效的学籍，在有金额转入后，变为已生效学籍；
        lambdaUpdate()
                .set(!StudentRecordStateEnum.VALID.name().equals(studentRecord.getState()), StudentRecord::getState, StudentRecordStateEnum.VALID.name())
                .set(StudentRecord::getTransferFromAmount, amount)
                .set(StudentRecord::getBalanceAmountDue, balanceAmountDue)
                .eq(StudentRecord::getId, studentRecordId)
                .update();
        this.sentBalanceAmountDueChangeMessage(studentRecord, balanceAmountDue);
    }

    private StudentRecordJournalVo mapModel(StudentRecordJournalVoModel studentRecordJournalVoModel) {
        return new ObjectMapper().convertValue(studentRecordJournalVoModel, StudentRecordJournalVo.class);
    }

    private void processVos(List<StudentRecordJournalVo> vos) {
        if (vos == null || vos.isEmpty()) return;
        var orderIds = vos.stream().map(StudentRecordJournalVo::getOrderId).filter(Objects::nonNull).collect(Collectors.toSet());
        if (!orderIds.isEmpty()) {
            var orderList = orderMapper.selectList(new QueryWrapper<Order>().lambda().in(Order::getId, orderIds));
            var orderStateMap = orderList.stream().collect(Collectors.toMap(Order::getId, Order::getState));
            var orderNumberMap = orderList.stream().collect(Collectors.toMap(Order::getId, Order::getOrderNo));
            for (StudentRecordJournalVo vo : vos) {
                if (org.springframework.util.StringUtils.hasText(vo.getOrderId())) {
                    var stateString = orderStateMap.get(vo.getOrderId());
                    if (org.springframework.util.StringUtils.hasText(stateString)) {
                        var state = OrderStateEnum.valueOf(stateString);
                        vo.setOrderState(state);
                    }
                    var orderNumber = orderNumberMap.get(vo.getOrderId());
                    vo.setOrderNo(orderNumber);
                }
            }
        }
        var accountIdSet = vos.stream().map(StudentRecordJournalVo::getCreatedBy)
                .filter(Objects::nonNull)
                .filter(org.springframework.util.StringUtils::hasText)
                .collect(Collectors.toSet());
        var accountMap = accountIdSet.stream().distinct().map(msasManager::getAccount)
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(AccountDto::getUsername, x -> x));
        for (StudentRecordJournalVo vo : vos) {
            var account = accountMap.get(vo.getCreatedBy());
            if (account != null) {
                vo.setCreatedByName(account.getName());
                vo.setCreatedByAndName(formatAccount(account));
            }
        }
        var journalIdSet = vos.stream().map(StudentRecordJournalVo::getJournalId).filter(Objects::nonNull).collect(Collectors.toSet());
        if (!journalIdSet.isEmpty()) {
            var forms = approvalFormMapper.findNewestFormByJournalIds(journalIdSet);
            var formMap = forms.stream().collect(Collectors.toMap(ApprovalForm::getJournalId, x -> x));
            for (StudentRecordJournalVo vo : vos) {
                var form = formMap.get(vo.getJournalId());
                if (form != null) {
                    vo.setFormId(form.getId());
                    vo.setFormState(form.getState());
                }
            }
        }
    }

    @Override
    public void syncSjc(Collection<String> recordIdCollection) {
        if (CollectionUtils.isEmpty(recordIdCollection)) {
            return;
        }
        List<StudentRecord> studentRecords = super.listByIds(recordIdCollection);
        if (CollectionUtils.isEmpty(studentRecords)) {
            return;
        }
        for (StudentRecord studentRecord : studentRecords) {
            var studentId = studentRecordStudentRelationshipService.findStudentId(studentRecord.getId());
            if (studentId != null) {
                var sjcId = studentJoinClassMapper.selectStudentJoinClassId(studentId, studentRecord.getClazzId());
                if (studentRecord.getSource().equals("SUSPENSION")) {
                    var currentClazz = e2ClazzMapper.selectByClazzId(studentRecord.getClazzId());
                    if (currentClazz.getSuspensionFlag()) {
                        var originStudentRecord = getBaseMapper().selectById(studentRecord.getAssociatedRecordId());
                        if (originStudentRecord != null) {
                            sjcId = studentJoinClassMapper.selectStudentJoinClassId(studentId, originStudentRecord.getClazzId());
                        }
                    }
                }
                if (sjcId != null) {
                    updateSjcId(studentRecord.getId(), sjcId);
                }
            }
        }
    }

    private void updateSjcId(String id, Integer sjcId) {
        getBaseMapper().update(
                null,
                new UpdateWrapper<StudentRecord>()
                        .lambda()
                        .eq(StudentRecord::getId, id)
                        .set(StudentRecord::getOldEmsRecordId, sjcId)
        );
    }
}
